package com.andaily.hb.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * 2024/1/7 22:57
 *
 * @author Shengzhao Li
 * @since 3.0.0
 */
public class TcpServer {

    private static final Logger LOG = LoggerFactory.getLogger(TcpServer.class);


    private boolean running;


    private final int port;

    public TcpServer(int port) {
        this.port = port;
    }

    public int getPort() {
        return port;
    }

    public void start() {
        try {
            Selector selector = Selector.open();
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.socket().bind(new InetSocketAddress(port));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            running = true;
            LOG.info("TCP Server is running on port {}", port);
            while (running) {
                if (selector.select() <= 0) {
                    continue;
                }

                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();
                    keyIterator.remove();

                    if (key.isAcceptable()) {
                        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                        SocketChannel clientChannel = serverChannel.accept();
                        clientChannel.configureBlocking(false);
                        clientChannel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) {
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        int bytesRead = clientChannel.read(buffer);
                        if (bytesRead == -1) {
                            clientChannel.close();
                            key.cancel();
                            continue;
                        }
                        buffer.flip();
                        byte[] data = new byte[buffer.limit()];
                        buffer.get(data);
                        LOG.info("Received from client: {}, data: {}", clientChannel, new String(data));
                        // Echo back to the client
                        clientChannel.write(ByteBuffer.wrap("OK!".getBytes()));
                    }
                }
            }
        } catch (IOException e) {
            LOG.error("Tcp-Server error", e);
        }
    }


    public void stop() {
        running = false;
        LOG.info("TCP Server is stop, running:{}", running);
    }
}


